# coding: utf-8
# author: t_wolf
# 公共装饰器方法

from comm_utils import *


# 为方法设置执行延迟,返回一个Timer方法
# 被装饰器处理的方法,需要使用.start()启动原方法执行
def set_timeout(seconds):
    def get_func(func):
        def _func(*args, **kwargs):
            return Timer(seconds, func, args, kwargs)

        return _func

    return get_func


def set_interval(seconds):
    def get_func(func):
        def _func(*args, **kwargs):
            func(*args, **kwargs)

        return _func

    return get_func


def override(func):
    """
    A decorator
    :param func: function
    :return: None
    """

    def on_call(self, *args, **kwargs):
        raise RuntimeError(
            "%s at [%s.%s] must be override." % (
                get_abs_path(CALL_FILE_POSITION), self.__class__.__name__, func.__name__
            )
        )

    return on_call


def runtime_statistic(func):
    """
    this is an Decorator.
    :param func: function object.
    :return: a dict has two key: 'result' is return by function, and 'runtime' is an statistic time.
    """

    def _runtime_get(*arg1, **arg2):
        _start = time.clock()
        return {
            'result': func(*arg1, **arg2),
            'runtime': (time.clock() - _start)
        }

    return _runtime_get


def check_args(**kwargs):
    """
    检查函数入参
    :param kwargs: 入参对象
    :return: 返回是否成功
    """
    fixed = 'args_num' in kwargs
    least = 'at_least' in kwargs
    types = 'arg_type' in kwargs
    rangs = 'arg_range' in kwargs

    args_length = kwargs.get('args_num', kwargs.get('at_least', 0))
    args_types = kwargs.get('arg_type', [])
    args_range = kwargs.get('arg_range', [])
    on_error = kwargs.get('on_error', None)

    iter_types = iter(args_types)
    iter_range = iter(args_range)

    def func_wrap(func):
        def func_args_wrap(*fa, **fkw):
            if (fixed and len(fa) != args_length) or (least and len(fa) < args_length):
                if callable(on_error):
                    on_error()
                else:
                    raise ValueError("Wrong Input Arguments.")

            if (types and len(fa) != len(args_types)) or (rangs and len(fa) != len(args_range)):
                if callable(on_error):
                    on_error()
                else:
                    raise ValueError("Wrong Input Arguments.")

            for arg in fa:
                if ((types and isinstance(arg, iter_types.next())) or not types) and \
                        ((rangs and arg in iter_range.next()) or not rangs):
                    continue

                if callable(on_error):
                    on_error()
                else:
                    raise ValueError("Wrong Input Arguments Types.")

            try:
                func(*fa, **fkw)
            except Exception:
                on_error()

        return func_args_wrap

    return func_wrap


def bond_thread(sync_sign):
    pass
